﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Collections.ObjectModel;
using Framework.Constructor.Sql;
using System.Xml;

namespace Framework.Constructor
{
    public class Configuracion
    {
        public ConnectionStringSettings ConnectionStringSettings { get; set; }
        public BaseDeDatos BaseDeDatos { get; set; }
        public Esquema Esquema { get; set; }
        public Collection<Tabla> Tablas { get; set; }
        public Collection<Vista> Vistas { get; set; }
        public Collection<Procedimiento> Procedimientos { get; set; }
        public Type Tipo { get; set; }
        public ObjetoBase Seleccionado { get; set; }
        public Collection<Type> Tipos { get; set; }
        public String NameSpace
        { 
            get 
            {
                return String.Format( "{0}.{1}", this.ConnectionStringSettings.Name, this.BaseDeDatos.Name );
            } 
        }
        public String Modulo
        {
            get
            {
                return this.Esquema.Name;
            }
        }
        public Configuracion( String setting )
        {
            this.ConnectionStringSettings = Configuracion.Obtener( ObtenerConnectionStringName( setting ) );
            this.BaseDeDatos = ObtenerBaseDeDatos( setting );
            this.Esquema = ObtenerEsquema( setting );
            this.Tablas = ObtenerTablas( setting );
            this.Vistas = ObtenerVistas( setting );
            this.Procedimientos = ObtenerProcedimientos( setting );
            this.Tipo = ObtenerTipo( setting );
            this.Seleccionado = ObtenerSeleccionado( setting );
            this.LoadTipos();
        }

        #region Private Methods
        private void LoadTipos()
        {
            if ( this.Tipos == null )
                this.Tipos = new Collection<Type>();
            if ( this.Seleccionado != null )
            {
                AddTipo( this.Seleccionado );
            }
            else if ( this.Tipo != null )
            {
                if ( this.Tipo == typeof( Tabla ) )
                    foreach ( Tabla item in this.Tablas )
                        AddTipo( item );
                if ( this.Tipo == typeof( Vista ) )
                    foreach ( Vista item in this.Vistas )
                        AddTipo( item );
                if ( this.Tipo == typeof( Procedimiento ) )
                    foreach ( Procedimiento item in this.Procedimientos )
                        AddTipo( item );
            }
            else
            {
                if ( this.Tablas != null )
                {
                    foreach ( Tabla item in this.Tablas )
                        AddTipo( item );
                }
                if ( this.Vistas != null )
                {
                    foreach ( Vista item in this.Vistas )
                        AddTipo( item );
                }
                if ( this.Procedimientos != null )
                {
                    foreach ( Procedimiento item in this.Procedimientos )
                        AddTipo( item );
                }
            }
        }

        private void AddTipo( ObjetoBase objeto )
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml( objeto.ToXmlString( "" ) );
            this.Tipos.Add( Reflection.ObtenerTipo( this.NameSpace, this.Modulo, doc.FirstChild ) );
        }
        
        private Framework.Constructor.Sql.ObjetoBase ObtenerSeleccionado( String setting )
        {
            String[] res = setting.Split( ';' );
            if ( res.Length > 4 )
            {
                return ObtenerObjeto( res[4] );
            }
            else
                return null;
        }

        private ObjetoBase ObtenerObjeto( String nombre )
        {
            ObjetoBase resultado = null;
            
            if (this.Tipo == typeof(Tabla))
                foreach ( Tabla item in this.Tablas )
                {
                    if ( item.Name.ToLowerInvariant() == nombre.ToLowerInvariant() )
                    {
                        resultado = item;
                        break;
                    }
                }
            if (this.Tipo == typeof(Vista))
                foreach(Vista item in this.Vistas)
                    if ( item.Name.ToLowerInvariant() == nombre.ToLowerInvariant() )
                    {
                        resultado = item;
                        break;
                    }
            if ( this.Tipo == typeof(Procedimiento))
                foreach ( Procedimiento item in this.Procedimientos)
                    if ( item.Name.ToLowerInvariant() == nombre.ToLowerInvariant() )
                    {
                        resultado = item;
                        break;
                    }
            return resultado;
        }

        private Type ObtenerTipo( String setting )
        {
            Type resultado = null;
            String[] res = setting.Split( ';' );
            if ( res.Length > 3 )
            {
                switch ( res[3].ToString() )
                { 
                    case "Tabla":
                        resultado = typeof(Tabla);
                        break;
                    case "Vista":
                        resultado = typeof(Vista);
                        break;
                    case "Procedimiento":
                        resultado = typeof(Procedimiento);
                        break;
                }
                
            }
            return resultado;
        }

        private Collection<Framework.Constructor.Sql.Procedimiento> ObtenerProcedimientos( String setting )
        {
            return Dao.ObtenerProcedimientos( this.ConnectionStringSettings, this.BaseDeDatos, this.Esquema );
        }

        private Collection<Framework.Constructor.Sql.Vista> ObtenerVistas( String setting )
        {
            return Dao.ObtenerVistas( this.ConnectionStringSettings, this.BaseDeDatos, this.Esquema );
        }

        private Collection<Framework.Constructor.Sql.Tabla> ObtenerTablas( String setting )
        {
            return Dao.ObtenerTablas( this.ConnectionStringSettings, this.BaseDeDatos, this.Esquema );
        }

        private Framework.Constructor.Sql.Esquema ObtenerEsquema( String setting )
        {
            String[] resultado = setting.Split( ';' );
            if ( resultado.Length > 2 )
                return Dao.ObtenerEsquema( this.ConnectionStringSettings, this.BaseDeDatos, resultado[2] );
            else
                return null;
        }

        private Framework.Constructor.Sql.BaseDeDatos ObtenerBaseDeDatos( String setting )
        {
            String[] resultado = setting.Split( ';' );
            if ( resultado.Length > 1 )
                return Dao.ObtenerBase( this.ConnectionStringSettings, resultado[1] );
            else
                return null;
        }

        private string ObtenerConnectionStringName( String setting )
        {
            String[] resultado = setting.Split( ';' );
            if ( resultado.Length > 0 )
                return resultado[0];
            else
                return null;
        }
        #endregion

        #region Public Static Methods
        public static Collection<ConnectionStringSettings> ObtenerOrigenes()
        {
            Collection<ConnectionStringSettings> resultado = new Collection<ConnectionStringSettings>();
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            foreach (ConnectionStringSettings cs in config.ConnectionStrings.ConnectionStrings)
            {
                resultado.Add(cs);
            }
            return resultado;
        }
        public static ConnectionStringSettings Obtener(String nombre)
        {
            ConnectionStringSettings resultado = null;
            foreach (ConnectionStringSettings conexion in ObtenerOrigenes())
            {
                if (conexion.Name.ToLowerInvariant() == nombre.ToLowerInvariant())
                {
                    resultado = conexion;
                    break;
                }
            }
            return resultado;
        }
        public static Boolean GuardarOrigen(ConnectionStringSettings origen)
        {
            Boolean resultado = false;
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                config.ConnectionStrings.ConnectionStrings.Add(origen);
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("ConnectionStrings");
                resultado = true;
            }
            catch { }
            return resultado;
        }
        public static Boolean BorrarOrigen(String nombre)
        {
            Boolean resultado = false;
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                config.ConnectionStrings.ConnectionStrings.Remove(nombre);
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("ConnectionStrings");
                resultado = true;
            }
            catch { }
            return resultado;        
        }
        public static String ObtenerConfiguracion( String key )
        {
            String resultado = String.Empty;
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None );
                resultado = config.AppSettings.Settings[key].ToString();
            }
            catch { }
            return resultado;            
        
        }
        public static Boolean BorrarConfiguracion( String key )
        {
            Boolean resultado = false;
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None );
                config.AppSettings.Settings.Remove( key );
                config.Save( ConfigurationSaveMode.Modified );
                ConfigurationManager.RefreshSection( "AppSettings" );
                resultado = true;
            }
            catch { }
            return resultado;
        }
        public static Collection<String> ObtenerConfiguraciones()
        {
            Collection<String> resultado = new Collection<String>();
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None );
                foreach ( KeyValueConfigurationElement kvce in config.AppSettings.Settings )
                {
                    if ( kvce.Key.StartsWith( "Objeto_" ) )
                        resultado.Add( kvce.Value );
                }
            }
            catch { }
            return resultado;
        }
        public static Boolean GuardarConfiguracion( KeyValuePair<String, String> setting )
        {
            BorrarConfiguracion( setting.Key );
            Boolean resultado = false;
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None );
                config.AppSettings.Settings.Add( setting.Key, setting.Value );
                config.Save( ConfigurationSaveMode.Modified );
                ConfigurationManager.RefreshSection( "AppSettings" );
                resultado = true;
            }
            catch { }
            return resultado;
        }
        #endregion
    }
}
